﻿using System;
using System.Linq.Expressions;
using MicroDal;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MicroDalTests
{
    [TestClass]
    public class MapGeneratorTest
    {
        [TestMethod]
        public void ShouldOnlyMapWriteablePublicProperties()
        {
            var sut = MapGenerator.DbDataReaderMapper<TestObject>();
            MemberInitExpression body = sut.Body as MemberInitExpression;

            Assert.AreEqual(3, body.Bindings.Count);
            Assert.AreEqual("ReadWriteProperty", body.Bindings[0].Member.Name);
            Assert.AreEqual("WriteOnlyProperty", body.Bindings[1].Member.Name);
        }

        [TestMethod, Ignore()]// How do we implement this
        public void ShouldMapStringColumnToImplicitObject()
        {
            var name = "The IMan";
            var sut = MapGenerator.DbDataReaderMapper<TestObject>();

            var result = sut.Compile()(new TestDbReader("ReadWriteProperty", DBNull.Value, "ReadOnlyProperty", DBNull.Value, "WriteOnlyProperty", DBNull.Value, "Foo", name.ToString()));

            Assert.IsNotNull(result.Foo);
            Assert.AreEqual(name, result.Foo.Name);
        }

        [TestMethod]
        public void ShouldMapStructs()
        {
            var sut = MapGenerator.DbDataReaderMapper<Point>();
            var meth = sut.Compile();

            var result = meth(new TestDbReader("x", 123, "y", 456));

            Assert.AreEqual(123, result.X);
            Assert.AreEqual(456, result.Y);
        }

        [TestMethod]
        public void ShouldMapWithParameterlessConstructor()
        {
            var testStr = "Test #1";
            var sut = MapGenerator.DbDataReaderMapper<Bar>();
            var meth = sut.Compile();

            var result = meth(new TestDbReader("Foo", testStr));

            Assert.AreEqual(testStr, result.Foo);
        }

        [TestMethod]
        public void ShouldMapWithConstructorWithMostArgs()
        {
            var testStr = "Test #1";
            var sut = MapGenerator.DbDataReaderMapper<Bar2>();
            var meth = sut.Compile();

            var result = meth(new TestDbReader("foo", testStr, "arg2", null));

            Assert.AreEqual(testStr, result.Foo);
        }
    }

    public class TestObject
    {
        public int ReadWriteProperty { get; set; }
        public int ReadOnlyProperty { get; private set; }
        public int WriteOnlyProperty { private get; set; }

        public Foo Foo { get; set; }
    }

    public class Foo
    {
        public static implicit operator Foo(string str)
        {
            return new Foo { Name = str };
        }

        public string Name { get; set; }
    }

    public struct Point
    {
        public Point(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
        public int X, Y;
    }

    public class Bar
    {
        public Bar() { }
        public Bar(string bar)
        {
            throw new NotImplementedException();
        }

        public string Foo { get; set; }
    }

    public class Bar2
    {
        public Bar2(string foo)
        {
            throw new NotImplementedException();
        }

        public Bar2(string foo, string arg2)
        {
            this.Foo = foo;
        }

        public string Foo { get; set; }
    }
}
